package geneticsatsolver;

import java.util.Random;

/**
 * Class GeneticOp provides method for mutation and crossover
 * 
 * @author igor
 */
public class GeneticOp {

    private double mutationRate;
    private int crossovertype;
    private double crossrate;

    /**
     * Initialize the Genetic Operation Class with
     * specified parameter
     *
     * @param mutrate mutation rate
     * @param crosstype crossover type
     * @param crrate corssover rate
     */
    GeneticOp(double mutrate, int crosstype, double crrate) {
        this.mutationRate = mutrate;
        this.crossovertype = crosstype;
        this.crossrate = crrate;
    }

    /**
     * Generate offspings from two individuals based on
     * crossover rate and crossover type
     *
     * @param father first parent
     * @param mother second parent
     * @return      offsprings
     */
    public Individual[] crossover(Individual father, Individual mother) {
        Individual[] sons = new Individual[2];
        if (Math.random() <= crossrate) {
            int len = father.len;

            boolean[] son1chromosome = new boolean[father.len];
            boolean[] son2chromosome = new boolean[father.len];

            if (crossovertype == 1) {
                boolean[] map = new boolean[len];
                Random r = new Random();
                for (int i = 0; i < len; i++) {
                    map[i] = r.nextBoolean();
                }


                for (int i = 0; i < father.len; i++) {
                    son1chromosome[i] = ((father.getChromosome()[i] && map[i]) || (mother.getChromosome()[i] && !map[i]));
                    son2chromosome[i] = ((mother.getChromosome()[i] && map[i]) || (father.getChromosome()[i] && !map[i]));
                }

            } else {
                {
                    int p = (int) (Math.random() * father.len);

                    for (int i = 0; i < father.len; i++) {
                        if (i < p) {
                            son1chromosome[i] = father.getChromosome()[i];
                            son2chromosome[i] = mother.getChromosome()[i];
                        } else {
                            son2chromosome[i] = father.getChromosome()[i];
                            son1chromosome[i] = mother.getChromosome()[i];
                        }
                    }
                }
            }

            sons[0] = new Individual(son1chromosome);
            sons[1] = new Individual(son2chromosome);
        } else {
            sons[0] = father;
            sons[1] = mother;
        }
        return sons;
    }

    /**
     * Perform mutation of an individual
     * based on mutation rate
     *
     * @param ind individual
     */
    public void mutate(Individual ind) {
        if (Math.random() <= mutationRate) {
            ind.mutate();
        }
    }
}
